import { IContextDescriptionItem } from '@/apis/chat/interfaces'
import {
    asm,
    fibonacci,
    initStack,
    movePointer,
    pc,
    regs,
    stack,
} from './asm-source'
import { globalConfig } from './config'
import { uiItems } from './uiItems'
import { getHex, getMemoryItem } from './utils'

// 初始化，渲染初始的代码，汇编代码，寄存器，pc，内存
let renderer = {
    asm() {
        const { codeArea, codeItem } = uiItems
        for (let i = 0; i < asm.length; i++) {
            let it = asm[i]

            let item = getMemoryItem(codeItem, it.add, it.asmCode)
            codeArea.add(item)
        }
        codeItem.remove()
    },
    regs() {
        const keys = Object.keys(regs)
        const { regArea, regItem } = uiItems
        for (const it of keys) {
            const item = getMemoryItem(
                regItem,
                it,
                regs[it as keyof typeof regs]
            )
            regArea.add(item)
        }
        const pcItem = getMemoryItem(regItem, 'pc', pc.get())
        regArea.add(pcItem)
        regItem.remove()
    },
    stack() {
        const { stackArea, stackItem } = uiItems

        for (let i = 0; i < stack.length; i++) {
            const it = stack[i]
            const item = getMemoryItem(stackItem, it[0], it[1])
            stackArea.add(item)
        }
        stackItem.remove()
    },
    cCodes() {
        // function _getCodeLineDom(val, i) {
        //     let dom = document.createElement('DIV')
        //     let lineNum = document.createElement('DIV')
        //     let code = document.createElement('DIV')
        //     dom.className = `code-line line-${i}`
        //     lineNum.textContent = i
        //     lineNum.className = 'line-number'
        //     if (val[0] === '\t') {
        //         code.classList.add('indent-1')
        //     }
        //     code.textContent = val
        //     dom.appendChild(lineNum)
        //     dom.appendChild(code)
        //     return dom
        // }
        // let frag = document.createDocumentFragment()
        // for (let i = 0; i < cCodes.length; i++) {
        //     let it = cCodes[i]
        //     let dom = _getCodeLineDom(it.code, it.add)
        //     dom.dataset.i = i
        //     frag.appendChild(dom)
        // }
        // $('.c-code').appendChild(frag)
    },
}
// 渲染
async function initRender() {
    renderer.asm()
    renderer.regs()
    renderer.stack()
    renderer.cCodes()
    // 移动页面中的各种指针到合适的位置

    movePointer('pc', pc.get())
    await movePointer('esp', regs.esp)
}

/**
 * 执行下一步
 */
export const handleNext = async () => {
    if (globalConfig.done) {
        return 'done'
    }
    if (!globalConfig.running) {
        globalConfig.running = true
        return 'unrunning'
    }
    if (!globalConfig.clickable) {
        return
    }
    globalConfig.clickable = false
    let i = pc.getIndex()
    let res: string | void = ''
    res = await asm[i].anime()

    if (res === 'done') {
        globalConfig.done = true
        // $('.btn-pause').classList.add('hide')
        // $('.btn-next').classList.add('hide')
        // $('.btn-one-step').classList.add('hide')
        return 'done'
    }
    globalConfig.clickable = true
}

export const handleOneStep = async () => {
    globalConfig.running = true
    let res: string | undefined = ''
    while (res !== 'done' && res !== 'unrunning') {
        res = await handleNext()
    }
}

/**
 * 初始化数据
 */
const initAll = async () => {
    globalConfig.running = false
    globalConfig.done = true
    let speed = globalConfig.speed
    globalConfig.speed = 0

    regs.esp = globalConfig.initialEsp
    regs.ebp = globalConfig.initialEsp + 40

    fibonacci.initial = globalConfig.an
    fibonacci.paramStack = []
    fibonacci.cmpl = undefined

    initStack([])

    // 删除页面中的所有memory-item
    // for (const it of $('.memory-item')) {
    //     it.remove()
    // }
    // for (const it of $('.code-line')) {
    //     it.remove()
    // }

    // 更新asm
    asm.findIndex((v) => {
        if (v.add === 0x804844a) {
            v.asmCode = `movl   $${getHex(globalConfig.an)},(%esp)`
            v.text = `movl   $${getHex(
                globalConfig.an
            )},(%esp) 指令会把数字${getHex(globalConfig.an)}放到内存中(%esp)处`
            return true
        } else {
            return false
        }
    })
    // 更新c-code
    // cCodes[7].code = `\tint i = f(${globalConfig.an})`

    await initRender()

    await Promise.all([
        movePointer('esp', regs.esp),
        movePointer('ebp', regs.ebp),
        pc.set(0x804844a),
        // cCodeAction.setPC(7),
    ])

    // $('.btn-pause').classList.add('hide')
    // $('.btn-one-step').classList.remove('hide')
    // $('.btn-next').classList.remove('hide')
    // $('.btn-reload').classList.add('hide')

    // setOutput('输出结果：')

    // treeConfig.n = globalConfig.an
    // $('.ipt-an').value = globalConfig.an
    // initTree()

    // checkoutMinimal(globalConfig.minimal)

    globalConfig.done = false
    globalConfig.running = true
    globalConfig.clickable = true
    globalConfig.speed = speed
}

initAll()

export const getContextDescription: () => IContextDescriptionItem[] = () => {
    const caseStatusInfo = `
各个寄存器的值：
| 寄存器 | 值 |
| ------ | -- |
${Object.keys(regs)
    .map((v) => {
        return `| ${v} | ${getHex(regs[v as keyof typeof regs])} |`
    })
    .join('\n')}
| pc     | ${getHex(pc.get())} |

代码区中的代码以及作用：
| 地址 | 代码 | 作用 |
| ---- | ---- | ---- |
${asm
    .map((v) => {
        return `| ${getHex(v.add)} | ${v.asmCode} | ${v.text} |`
    })
    .join('\n')}
`

    console.log(caseStatusInfo)

    return [
        {
            key: 'caseTitle',
            value: '斐波拉契数列运行时的栈变化',
        },
        {
            key: 'caseDescription',
            value: '此案例演示了求斐波拉契数列的第n项的代码运行过程中的栈内容的变化，通过分析各个寄存器的值和代码区中的指令，可以了解函数调用、参数传递及局部变量存储的过程。',
        },
        // {
        //     key: 'caseStatusInfo',
        //     value: caseStatusInfo,
        // },
    ]
}
